package com.zan.zanchat.common.user.service.impl;

import cn.hutool.jwt.JWT;
import com.zan.zanchat.common.common.constant.RedisKey;
import com.zan.zanchat.common.common.utils.JwtUtils;
import com.zan.zanchat.common.common.utils.RedisUtils;
import com.zan.zanchat.common.user.service.LoginService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Author Zan
 * @Create 2024/3/8 17:38
 * @Description :
 */
@Service
public class LoginServiceImpl implements LoginService {

    public static final int TOKEN_EXPIRE_DAYS = 3;
    public static final int TOKEN_RENEWAL_DAYS = 1;

    @Resource
    private JwtUtils jwtUtils;

    /**
     * 刷新token有效期, 异步刷新
     */
    @Override
    @Async // 将该方法用Spring进行包装，
    public void renewalTokenIfNecessary(String token) {
        // 获取token是否有效
        Long uid = getValidUid(token);
        // 生成key
        String userTokenKey = getUserTokenKey(uid);
        Long expireDays = RedisUtils.getExpire(userTokenKey, TimeUnit.DAYS);
        if (expireDays == -2) { // key不存在的情况
            return;
        }
        if (expireDays < TOKEN_RENEWAL_DAYS) {
            // 进行续期
            RedisUtils.expire(getUserTokenKey(uid), TOKEN_EXPIRE_DAYS, TimeUnit.DAYS);
        }
    }

    @Override
    public String login(Long uid) {
        // 这里jwt不用设置过期时间，最后的中心化来进行设置过期和续期
        String token = jwtUtils.createToken(uid);
        RedisUtils.set(getUserTokenKey(uid), token, TOKEN_EXPIRE_DAYS, TimeUnit.DAYS);
        return token;
    }

    /**
     * 校验token是不是有效
     */
    @Override
    public Long getValidUid(String token) {
        Long uid = jwtUtils.getUidOrNull(token);
        if (Objects.isNull(uid)) {
            return null;
        }
        // 获取token - 从redis缓存中找，如果有说明token仍然有效，可以继续保持登录状态
        String oldToken = RedisUtils.get(getUserTokenKey(uid), String.class);
        // 不为空，说明在有效期之内 - 排除当从另一个地方登录，生成新的token导致有重复的token，旧的token不能被获取到，因此需要判断旧token与新token是否一致
        // 而不是拿到token就好啦，判断其有值找到了就好
        return Objects.equals(oldToken, token) ? uid : null;
    }


    /**
     * 生成自定义的UserTokenKey
     */
    public String getUserTokenKey(Long uid) {
        return RedisKey.getKey(RedisKey.USER_TOKEN_STRING, uid);
    }
}
